package com.petrooil.web.controller;

import com.petrooil.core.dao.OrbeonDao;
import com.petrooil.core.model.PetroOilDoc;
import com.petrooil.core.model.WorkflowRule;
import com.petrooil.core.model.controller.ModelFormDefinition;
import com.petrooil.core.model.controller.ModelPetroOilDoc;
import com.petrooil.core.model.session.SessionInfo;
import com.petrooil.core.service.IPetroOilDocService;
import com.petrooil.core.service.IWorkflowRuleService;
import com.petrooil.utils.JsonPagedDataAction;
import com.petrooil.utils.SysListUtils;
import com.petrooil.utils.SysLookup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class WorkflowController {

    @Autowired
    private IPetroOilDocService petroOilDocService;

    @Autowired
    private OrbeonDao orbeonDao;

    @Autowired
    private IWorkflowRuleService workflowRuleService;

    private String msg;

    private String error;

    @RequestMapping(value = "wf/getTasksList", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
    public @ResponseBody JsonPagedDataAction<ModelPetroOilDoc> getPetroDocList(HttpSession session) {
        JsonPagedDataAction<ModelPetroOilDoc> data = new JsonPagedDataAction<ModelPetroOilDoc>() {};
        String department = (String) session.getAttribute(SysLookup.SessionKey.DEPARTMENTS);

        Map<String,WorkflowRule> rulesMap = new HashMap<>();
        for (WorkflowRule rule : workflowRuleService.getRulesByDepartment(department)) {
            rulesMap.put(rule.getForm(), rule);
        }

        List<ModelPetroOilDoc> list = new ArrayList<>();
        for (PetroOilDoc doc : petroOilDocService.getPetroDocList(department)){
            ModelPetroOilDoc oilDoc = new ModelPetroOilDoc();
            if (rulesMap.get(doc.getForm()) != null) {
                oilDoc.setActions(rulesMap.get(doc.getForm()).getActions());
            } else {
                oilDoc.setActions("");
            }
            if (rulesMap.get(doc.getForm()) != null) {
                oilDoc.setFlows(rulesMap.get(doc.getForm()).getFlows());
            } else {
                oilDoc.setFlows("");
            }
            oilDoc.setDepartment(doc.getDepartment());
            oilDoc.setDescription(doc.getDescription());
            oilDoc.setDocumentId(doc.getDocumentId());
            oilDoc.setForm(doc.getForm());
            oilDoc.setOrbeonDocId(doc.getOrbeonDocId());
            oilDoc.setUsername(doc.getUsername());
            oilDoc.setName(doc.getName());
            list.add(oilDoc);
        }

        session.setAttribute(SysLookup.SessionKey.SESSION_INFO, new SessionInfo((long) list.size(), SysLookup.DEPARTMENT.valueOf(department).getDescription()));

        data.setData(list);
        return data;
    }

    @RequestMapping(value = {"/wf/tasks" }, method = RequestMethod.GET)
    public ModelAndView showTasks(HttpSession session){
        ModelAndView model = new ModelAndView();
        model.addObject("msg", msg);
        model.addObject("error", error);
        msg = "";
        error = "";
        model.setViewName("wf/tasks");
        return model;
    }

    @RequestMapping(value = "wf/getFormList", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
    public @ResponseBody JsonPagedDataAction<ModelFormDefinition> getFormDefinitionList(HttpSession session) {
        JsonPagedDataAction<ModelFormDefinition> data = new JsonPagedDataAction<ModelFormDefinition>() {};
        String department = (String) session.getAttribute(SysLookup.SessionKey.DEPARTMENTS);
        List<Map<String, String>> listForms = orbeonDao.getForms(department);

        List<ModelFormDefinition> list = new ArrayList<>();

        for (Map<String, String> map : listForms) {
            list.add(new ModelFormDefinition(
                    map.get(SysLookup.OrbeonColums.DEFINITION_APP),
                    map.get(SysLookup.OrbeonColums.DEFINITION_FORM),
                    SysLookup.DEPARTMENT.valueOf(map.get(SysLookup.OrbeonColums.DEFINITION_APP)).getDescription(),
                    map.get(SysLookup.OrbeonColums.DEFINITION_LAST_MODIFIED_BY)));
        }
        data.setData(list);
        return data;
    }

    @RequestMapping(value = {"/wf/forms" }, method = RequestMethod.GET)
    public ModelAndView showForms() {
        ModelAndView model = new ModelAndView();
        model.setViewName("wf/forms");
        return model;
    }

    @RequestMapping(value = {"/wf/archiveTask" }, method = RequestMethod.GET)
    public ModelAndView archiveTask(@RequestParam(value="task", required=true) Integer id) {
        ModelAndView model = new ModelAndView();
        PetroOilDoc doc = petroOilDocService.get(id);

        if (doc == null) {
            error = "Nie ma takiego dokumentu.";
        } else {
            doc.setDepartment(SysLookup.DEPARTMENT.ARCHIVE.toString());
            petroOilDocService.update(doc);
            msg = "Przeniesiono do archiwum.";
        }
        model.setViewName("redirect:/wf/tasks");
        return model;
    }

    @RequestMapping(value = {"/wf/removeTask" }, method = RequestMethod.GET)
    public ModelAndView removeTask(@RequestParam(value="task", required=true) Integer id) {
        ModelAndView model = new ModelAndView();
        PetroOilDoc doc = petroOilDocService.get(id);

        if (doc == null) {
            error = "Nie ma takiego dokumentu.";
        } else {
            doc.setDepartment(SysLookup.DEPARTMENT.TRASH.toString());
            petroOilDocService.update(doc);
            msg = "Przeniesiono do kosza.";
        }
        model.setViewName("redirect:/wf/tasks");
        return model;
    }

    @RequestMapping(value = {"/wf/doTask" }, method = RequestMethod.GET)
    public ModelAndView doTask(@RequestParam(value="task", required=true) Integer id, HttpSession session) {
        ModelAndView model = new ModelAndView();
        String department = (String) session.getAttribute(SysLookup.SessionKey.DEPARTMENTS);
        PetroOilDoc doc = petroOilDocService.get(id);
        WorkflowRule rule = workflowRuleService.getRuleByFormAndDep(doc.getForm(), department);

        if (doc == null || rule == null || rule.getFlows() == null || rule.getFlows().isEmpty()) {
            error = "Brak takiego dokumentu lub nie ma zdefiniowanego workflow dla tego dokumentu";
            model.setViewName("redirect:/wf/tasks");
            return model;
        }

        model.addObject("flowsMap", flowsMap(rule.getFlows()));
        model.addObject("doc", doc);
        model.setViewName("wf/doTask");
        return model;
    }

    @RequestMapping(value = {"/wf/saveDoneTask" }, method = RequestMethod.POST)
    public ModelAndView saveWorkflowRuleList(@ModelAttribute("doc") PetroOilDoc doc) {
        ModelAndView model = new ModelAndView();
        PetroOilDoc petroOilDoc = null;

        if (doc.getDocumentId() != null) {
            petroOilDoc = petroOilDocService.get(doc.getDocumentId());
        } else if (petroOilDoc == null) {
            error = "Nie ma takiego dokumentu.";
            model.setViewName("redirect:/wf/tasks");
        }


        doc.setDescription(doc.getDescription());
        doc.setForm(petroOilDoc.getForm());
        doc.setUsername(petroOilDoc.getUsername());
        doc.setOrbeonDocId(petroOilDoc.getOrbeonDocId());
        petroOilDocService.update(doc);

        msg = "Zadanie zostało poprawnie przekazane dalej.";
        model.setViewName("redirect:/wf/tasks");
        return model;
    }


    private Map<String, String> flowsMap(String flows) {
        Map<String, String> map = new HashMap<>();
        for (String s : SysListUtils.stringToList(flows)) {
            SysLookup.DEPARTMENT dep = SysLookup.DEPARTMENT.valueOf(s);
            if (dep != null) {
                map.put(dep.toString(), dep.getDescription());
            }
        }
        return map;
    }
}
